package com.h2.ref.server.web.user.openid;

import java.util.Collection;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.openid.OpenIDAuthenticationToken;
import org.springframework.security.openid.OpenIDConsumerException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.h2.ref.server.user.UserService;
import com.h2.ref.server.user.model.User;
import com.h2.ref.server.user.openid.OpenId;
import com.h2.ref.server.user.openid.UserServiceOpenId;
import com.h2.ref.server.web.ViewConstants;

@Controller
public class OpenIdController {
   
   private static final Logger LOG = LoggerFactory.getLogger(
         OpenIdController.class);
   
   ////
   
   private UserService _userService;
   
   private UserServiceOpenId _openIdService;
   
   ////
   
   private OpenIdProvider _openIdProvider;
   
   ////
   ////
   
   @RequestMapping(value=ViewConstants.SETTINGS_OPENID,
         method=RequestMethod.GET)
   public String show(Model model) {
      User user = getUserService().getActiveUser();
      
      model.addAttribute("openIdList", getOpenIdService().findOpenIds(user));
      
      return ViewConstants.SETTINGS_OPENID_VIEW;
   }
   
   @RequestMapping(value=ViewConstants.SETTINGS_OPENID_ADD)
   public String show(HttpServletRequest request) {
      User user = getUserService().getActiveUser();
      
      String identity = request.getParameter("openid.identity");
      
      if (!StringUtils.hasText(identity)) {
         String claimedIdentity = getOpenIdProvider().obtainUsername(request);
         
         try {
            String redirectUrl = getOpenIdProvider().obtainIdentity(
                  request, claimedIdentity,
                  getOpenIdProvider().buildReturnToUrl(request));
            return ViewConstants.REDIRECT + redirectUrl;
         } catch (OpenIDConsumerException exp) {
            LOG.debug("Failed to consume claimedIdentity: " + claimedIdentity, exp);
            throw new AuthenticationServiceException(
                  "Unable to process claimed identity '" + claimedIdentity + "'");
         }
      }
      
      if (LOG.isDebugEnabled()) {
         LOG.trace("Supplied OpenID identity is " + identity);
      }
      
      OpenIDAuthenticationToken token;
      try {
         token = getOpenIdProvider().readIdentity(request);
      } catch (OpenIDConsumerException exp) {
         throw new AuthenticationServiceException("Consumer error", exp);
      }
      
      OpenId openId = new OpenId();
      openId.setUid(token.getIdentityUrl());
      openId.setUserId(user.getId());
      
      if (getOpenIdService().loadUserByUsername(token.getIdentityUrl()) != null) {
         //TODO
         return new StringBuffer()
            .append(ViewConstants.REDIRECT)
            .append(ViewConstants.SETTINGS_OPENID + ".html").toString();
      }
      getOpenIdService().addOpenId(openId);
      
      return new StringBuffer()
         .append(ViewConstants.REDIRECT)
         .append(ViewConstants.SETTINGS_OPENID + ".html").toString();
   }
   
   @RequestMapping(value=ViewConstants.SETTINGS_OPENID_REMOVE,
         method=RequestMethod.GET)
   public String deleteOpenId(@RequestParam(value="id", required=true) Long id) {
      
      User user = getUserService().getActiveUser();
      
      Collection<OpenId> results = getOpenIdService().findOpenIds(user);
      for (OpenId openId : results) {
         if(id.equals(openId.getId()) && user.getId().equals(openId.getUserId())) {
            getOpenIdService().deleteOpenId(openId);
         }
      }
      
      return new StringBuffer()
         .append(ViewConstants.REDIRECT)
         .append(ViewConstants.SETTINGS_OPENID + ".html").toString();
   }
   
   /**
    * Builds the <tt>return_to</tt> URL that will be sent to the OpenID service
    * provider. By default returns the URL of the current request.
    * 
    * @param request the current request which is being processed by this filter
    * @return The <tt>return_to</tt> URL.
    */
   protected String buildReturnToUrl(HttpServletRequest request) {
      return request.getRequestURL().toString();
   }

   /**
    * @return the userService
    */
   public UserService getUserService() {
      return _userService;
   }

   /**
    * @param userService the userService to set
    */
   public void setUserService(UserService userService) {
      _userService = userService;
   }

   /**
    * @return the openIdService
    */
   public UserServiceOpenId getOpenIdService() {
      return _openIdService;
   }

   /**
    * @param openIdService the openIdService to set
    */
   public void setOpenIdService(UserServiceOpenId openIdService) {
      _openIdService = openIdService;
   }

   /**
    * @return the openIdProvider
    */
   public OpenIdProvider getOpenIdProvider() {
      return _openIdProvider;
   }

   /**
    * @param openIdProvider the openIdProvider to set
    */
   public void setOpenIdProvider(OpenIdProvider openIdProvider) {
      _openIdProvider = openIdProvider;
   }

}
